﻿using System.Data;

namespace sinetd.Services.Modbus
{
    // http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf
    public class DataModel : DataSet
    {
        private DataTable[] memoryBanks;

        public DataModel(int dim, int di, int c, int ir, int ih)
        {
            memoryBanks = new DataTable[4];
            memoryBanks[(int)MemoryBanks.DiscreteInput] = new DataTable<bool>(di, dim);
            memoryBanks[(int)MemoryBanks.Coils] = new DataTable<bool>(c, dim);
            memoryBanks[(int)MemoryBanks.InputRegisters] = new DataTable<short>(ir, dim);
            memoryBanks[(int)MemoryBanks.HoldingRegisters] = new DataTable<short>(ih, dim);
            foreach (int i in System.Enum.GetValues(typeof(MemoryBanks)))
            {
                this.Tables.Add(memoryBanks[i]);
            }
        }

        public void Reload()
        {
            foreach (int i in System.Enum.GetValues(typeof(MemoryBanks)))
            {
                ((IDataTableReload)memoryBanks[i]).Reload();
            }
        }
    }

    public interface IDataTableReload
    {
        void Reload();
        void SetRawData(int i, int j, object val);
        void SetRawData(int i, object val);
        object GetRawData(int i, int j);
        object GetRawData(int i);
    }

    internal class DataTable<T> : DataTable, IDataTableReload
    {
        public DataTable(int size, int dim)
        {
            Dim = dim;
            RawData = new T[size];
            for (int c = 0; c < Dim; c++)
                this.Columns.Add(c.ToString(), typeof(T));
        }

        public int Dim;
        private T[] RawData;
        
        public new DataRowCollection Rows
        {
            get
            {
                int i = 0;
                while (i < RawData.Length)
                {
                    object[] item = new object[Dim];
                    for (int c = 0; c < Dim; c++)
                    {
                        if (i < RawData.Length)
                            item[c] = RawData[i++];
                    }
                    base.Rows.Add(item);
                }
                return base.Rows;
            }
        }

        #region IDataTableReload Members

        public void Reload()
        {
            int d = this.Rows.Count;
        }

        public void SetRawData(int i, int j, object val)
        {
            RawData[i * Dim + j] = (T)val;
        }

        public void SetRawData(int i, object val)
        {
            RawData[i] = (T)val;
        }

        public object GetRawData(int i, int j)
        {
            return RawData[i * Dim + j];
        }

        public object GetRawData(int i)
        {
            return RawData[i];
        }

        #endregion
    }
}
